import json
from datetime import datetime
import re
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from rest_framework_jwt.settings import api_settings
from django.db.models import Count
from Django_Emotion import settings
from menu.models import Menu, MenuSerializer
from role.models import Role
from user.models import User, UserSerializer, Stock_K, Stock_KSerializer, Stock_NLP
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser
import pandas as pd
import os
from openai import OpenAI


class LoginView(View):
    def buildTreeMenu(self, MenuList):
        resultMenuList: list[Menu] = list()
        for menu in MenuList:
            # 寻找子节点
            for e in MenuList:
                if e.parent_id == menu.id:
                    if not hasattr(menu, "children"):
                        menu.children = list()
                    menu.children.append(e)
            # 判断父节点，添加到集合
            if menu.parent_id == 0:
                resultMenuList.append(menu)
        return resultMenuList

    def post(self, request):
        username = request.GET.get("username")
        password = request.GET.get("password")
        try:
            user = User.objects.get(username=username, password=password)
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            # 将用户对象传递进去，获取到该对象的属性值
            payload = jwt_payload_handler(user)
            # 将属性值编码成jwt格式的字符串
            # token = jwt_encode_handler(payload)
            roleList = Role.objects.raw(
                "SELECT id ,NAME FROM role WHERE id IN (SELECT role_id FROM user_role WHERE user_id="
                + str(user.id)
                + ")"
            )
            # print(roleList)

            roles = ",".join([role.name for role in roleList])

            menuSet: set[Menu] = set()
            for row in roleList:
                # print(row.id, row.name)
                menuList = Menu.objects.raw(
                    "SELECT * FROM menu WHERE id IN (SELECT menu_id FROM role_menu WHERE role_id="
                    + str(row.id)
                    + ")"
                )
                for row2 in menuList:
                    # print(row2.id, row2.name)
                    menuSet.add(row2)
            # print(menuSet)
            menuList: list[Menu] = list(menuSet)  # set转list
            sorted_menuList = sorted(menuList)  # 根据order_num排序
            # print(sorted_menuList)
            # 构造菜单树
            sysMenuList: list[Menu] = self.buildTreeMenu(sorted_menuList)
            # print(sysMenuList)
            serializerMenuList = list()
            for sysMenu in sysMenuList:
                serializerMenuList.append(MenuSerializer(sysMenu).data)

        except Exception as e:
            print(e)
            return JsonResponse({"code": 500, "info": "用户名或者密码错误！"})
        return JsonResponse(
            {
                "code": 200,
                "user": UserSerializer(user).data,
                "info": "登录成功",
                "roles": roles,
                "menuList": serializerMenuList,
            }
        )
        # return JsonResponse(
        #     {'code': 200, 'token': token, 'user': UserSerializer(user).data, 'info': '登录成功', 'roles': roles,
        #      'menuList': serializerMenuList})


# Create your views here.
class TestView(View):

    def get(self, request):
        token = request.META.get("HTTP_AUTHORIZATION")
        if token != None and token != "":
            userList_obj = User.objects.all()
            print(userList_obj, type(userList_obj))
            userList_dict = userList_obj.values()  # 转存字典
            print(userList_dict, type(userList_dict))
            userList = list(userList_dict)  # 把外层的容器转存List
            print(userList, type(userList))
            return JsonResponse({"code": 200, "info": "测试！", "data": userList})
        else:
            return JsonResponse({"code": 401, "info": "没有访问权限！"})


class JwtTestView(View):

    def get(self, request):
        user = User.objects.get(username="python222", password="123456")
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        # 将用户对象传递进去，获取到该对象的属性值
        payload = jwt_payload_handler(user)
        # 将属性值编码成jwt格式的字符串
        token = jwt_encode_handler(payload)
        return JsonResponse({"code": 200, "token": token})


class SaveView(View):

    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        print(data)
        if data["id"] == -1:  # 添加
            pass
        else:  # 修改
            obj_sysUser = User(
                id=data["id"],
                username=data["username"],
                password=data["password"],
                avatar=data["avatar"],
                email=data["email"],
                phonenumber=data["phonenumber"],
                login_date=data["login_date"],
                status=data["status"],
                create_time=data["create_time"],
                update_time=data["update_time"],
                remark=data["remark"],
            )
            obj_sysUser.update_time = datetime.now().date()
            obj_sysUser.save()
        return JsonResponse({"code": 200})


class PwdView(View):

    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        id = data["id"]
        oldPassword = data["oldPassword"]
        newPassword = data["newPassword"]
        obj_user = User.objects.get(id=id)
        if obj_user.password == oldPassword:
            obj_user.password = newPassword
            obj_user.update_time = datetime.now().date()
            obj_user.save()
            return JsonResponse({"code": 200})
        else:
            return JsonResponse({"code": 500, "errorInfo": "原密码错误！"})


class ImageView(View):

    def post(self, request):
        file = request.FILES.get("avatar")
        print("file:", file)
        if file:
            file_name = file.name
            suffixName = file_name[file_name.rfind(".") :]
            new_file_name = datetime.now().strftime("%Y%m%d%H%M%S") + suffixName
            file_path = str(settings.MEDIA_ROOT) + "\\userAvatar\\" + new_file_name
            print("file_path:", file_path)
            try:
                with open(file_path, "wb") as f:
                    for chunk in file.chunks():
                        f.write(chunk)
                return JsonResponse({"code": 200, "title": new_file_name})
            except:
                return JsonResponse({"code": 500, "errorInfo": "上传头像失败"})


class AvatarView(View):

    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        id = data["id"]
        avatar = data["avatar"]
        obj_user = User.objects.get(id=id)
        obj_user.avatar = avatar
        obj_user.save()
        return JsonResponse({"code": 200})


class K_lineView(View):
    def get(self, request):
        code = request.GET.get("code", "000001")
        data = Stock_K.objects.filter(code=code)
        return JsonResponse(
            {"code": 200, "data": Stock_KSerializer(data, many=True).data}
        )


class GuBa_View(View):
    def get(self, request):
        code = request.GET.get("code", "000678")
        # print(code)
        # 计算该股吧各情感数量
        data = Stock_NLP.objects.filter(stock_code=code)
        stock_name = data[0].stock_name[:4]
        emo_count = data.values("emo").annotate(count=Count("emo")).order_by("emo")
        # 构建目标格式的字典
        pie_data = {}
        for item in emo_count:
            # 将 emo 的值作为键，数量作为值
            pie_data[item["emo"]] = item["count"]

        # 获取三个分类中代表语句
        # 获取所有不同的 emo 分类
        emo_categories = data.values_list("emo", flat=True).distinct()

        # 初始化结果字典
        text_example = {}

        # 遍历每个分类，获取每种分类下的两条内容
        for emo in emo_categories:
            # 获取当前分类下的两条内容
            items = data.filter(emo=emo)[:2]
            # 提取 data 字段的内容
            text_example[emo] = [item.data for item in items]
        return JsonResponse(
            {
                "code": 200,
                "stock_name": stock_name,
                "pie_data": pie_data,
                "text_example": text_example,
            }
        )


# views.py

import json

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import requests


class ChatView(APIView):
    def post(self, request):
        # 获取前端发送的用户消息
        user_message = request.data.get("message")
        if not user_message:
            return Response(
                {"error": "No message provided"}, status=status.HTTP_400_BAD_REQUEST
            )
        
        # 获取会话 ID（从请求中获取或初始化为 None）
        session_id = request.data.get("session_id")

        try:
            # 初始化阿里云百炼客户端
            client = OpenAI(
                api_key="sk-4ee65a55e989462482ea75ca42fc17cd",
                base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
            )

            # 调用阿里云百炼API
            completion = client.chat.completions.create(
                model="qwen-plus",  # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
                messages=[
                    {'role': 'system', 'content': '你是中国股票分析大师,请你用中文回答接下来的问题'},
                    {'role': 'user', 'content': user_message}
                ],
                stream=False,  # 设置为 False，直接返回完整响应
            )
            
            # 获取模型响应
            assistant_message = completion.choices[0].message.content
            print(assistant_message)
            
            # 如果响应包含</think>标签，提取有效内容
            think_match = re.findall(r"</think>(.*)", assistant_message, re.DOTALL)
            if think_match:
                assistant_message = think_match[0].strip()
            
            # 生成新的会话ID（如果需要）
            new_session_id = session_id if session_id else f"session_{hash(user_message) % 10000}"
            
        except Exception as e:
            print(f"API调用错误：{e}")
            return Response(
                {"error": f"API调用失败: {str(e)}"}, 
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        # 返回模型的响应和会话 ID
        return Response(
            {
                "message": assistant_message,
                "session_id": new_session_id,
            },
            status=status.HTTP_200_OK,
        )


class UploadView(APIView):
    authentication_classes = []  # 禁用认证
    parser_classes = [MultiPartParser]

    def post(self, request, format=None):
        file_obj = request.FILES.get("file")
        if not file_obj:
            return Response({"error": "No file uploaded"}, status=400)
        try:
            df = pd.read_csv(file_obj, encoding="utf-8", on_bad_lines="skip")
            data = df.head(10).to_dict(orient="records")
            print(data)
            return Response({"data": data})
        except Exception as e:
            print(e)
            return Response({"error": str(e)}, status=400)


class PredictView(APIView):
    def post(self, request):
        open_data = (
            Stock_K.objects.filter(code="000001")
            .order_by("-date")[:50]
            .values_list("open", flat=True)
        )
        # print(open_data)
        emo_data = (
            Stock_NLP.objects.filter(stock_code="000001")
            .order_by("-id")[:50]
            .values_list("emo", flat=True)
        )
        
        try:
            # 初始化阿里云百炼客户端
            client = OpenAI(
                api_key="sk-4ee65a55e989462482ea75ca42fc17cd",
                base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
            )

            # 调用阿里云百炼API
            completion = client.chat.completions.create(
                model="qwen-plus",  # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
                messages=[
                    {
                        "role": "system",
                        "content": "你是中国股票分析大师,请你用中文回答接下来的问题",
                    },
                    {
                        "role": "user",
                        "content": "请你基于我给出的近期股票收盘价和投资者情绪，预测未来50天内的股价走势，并给出预测的概率，要求有波动但不能整体上升或下降，第一个预测的股价要与给出的股价一致。请你用Python中列表形式给出：预测股价、预测正确的概率百分比。\n这是示例：预测股价:[20.0, 12.3, 18.6, 16.0, 18.6, 18.1, 12.5, 12.1, 20.7, 19.4, 15.1, 15.5, 12.9, 20.6, 15.5, 19.6, 13.7, 15.3, 17.2, 20.1, 12.5, 15.5, 15.0, 11.5, 16.8, 20.4, 20.5, 11.5, 15.5, 12.1, 15.1, 12.5, 16.0, 18.8, 10.7, 16.1, 17.9, 20.8, 20.6, 17.6, 10.5, 19.9, 12.3, 19.9, 13.0, 16.4, 19.8, 12.5, 18.1, 13.4],预测概率:['84.2%', '89.8%', '80.0%', '86.0%', '88.2%', '85.7%', '81.6%', '87.1%', '87.2%', '88.2%', '90.0%', '81.6%', '85.6%', '80.5%', '84.0%', '80.5%', '85.8%', '82.1%', '81.8%', '87.9%', '88.8%', '88.0%', '89.5%', '81.1%', '82.6%', '82.8%', '88.1%', '88.8%', '89.9%', '81.3%', '86.1%', '86.6%', '87.6%', '87.1%', '81.0%', '88.2%', '87.7%', '84.0%', '84.5%', '84.8%', '81.2%', '83.4%', '81.8%', '86.8%', '86.1%', '86.5%', '87.5%', '86.9%', '86.7%', '84.1%']。\n接下来分别是近期股票收盘价和投资者情绪走向。收盘价："
                        + str(open_data)
                        + "\n情绪走向："
                        + str(emo_data),
                    },
                ],
                stream=False,  # 设置为 False，直接返回完整响应
            )
            
            # 获取模型响应
            assistant_message = completion.choices[0].message.content
            # print(assistant_message)
            
            # 如果响应包含</think>标签，提取有效内容
            think_match = re.findall(r"</think>(.*)", assistant_message, re.DOTALL)
            if think_match:
                assistant_message = think_match[0].strip()
            
            # 解析预测数据
            floats = re.findall(r"\b\d+(?:\.\d+)?\b(?!%)", assistant_message)
            percents = re.findall(r"\b\d+(?:\.\d+)?%", assistant_message)
            # print(floats)
            # print(percents)
            min_len = min(len(floats), len(percents))
            floats = floats[:min_len]
            percents = percents[:min_len]
            print(floats)
            
        except Exception as e:
            print(f"API调用错误：{e}")
            return Response(
                {"error": f"API调用失败: {str(e)}"}, 
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        # 返回模型的响应和新的会话 ID
        return Response(
            {
                "len": min_len,
                "floats": floats,
                "percents": percents,
            },
            status=status.HTTP_200_OK,
        )


class StudentView(APIView):
    def post(self, request):
        topic = request.data.get("topic")  # 辩论题目
        user_side = request.data.get("user_side")  # 用户选择的立场（正/反）
        user_message = request.data.get("message")  # 用户的具体论点
        session_id = request.data.get("session_id")  # 会话ID，用于维持对话连续性
        
        print(f"辩论题目: {topic}")
        print(f"用户立场: {user_side}")
        print(f"用户论点: {user_message}")
        
        # 根据用户立场确定AI的立场
        ai_side = "反方" if user_side == "正方" else "正方"
        
        # 构建辩论系统提示词
        system_content = f"""
你是一位专业的辩论专家，现在正在进行一场关于"{topic}"的辩论。

辩论规则：
1. 你代表{ai_side}，用户代表{user_side}
2. 每次回复都要基于自己的立场进行论证
3. 使用逻辑推理、事实依据、类比论证等方法
4. 可以反驳对方的观点，但要保持礼貌和理性
5. 每次回复控制在200-300字左右
6. 要体现辩论的专业性和逻辑性

辩论技巧：
- 使用三段论、归纳推理等逻辑方法
- 引用相关数据、案例或权威观点
- 指出对方论证中的逻辑漏洞
- 强调己方立场的优势
- 保持论点的连贯性和一致性

请记住：你始终站在{ai_side}的立场上进行辩论，要坚定地维护自己的观点。
        """
        
        # 构建用户消息
        if user_message:
            user_content = f"作为{user_side}，我的观点是：{user_message}"
        else:
            user_content = f"我是{user_side}，请开始辩论。"
        
        try:
            # 初始化阿里云百炼客户端
            client = OpenAI(
                api_key="sk-4ee65a55e989462482ea75ca42fc17cd",
                base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
            )

            # 调用阿里云百炼API
            completion = client.chat.completions.create(
                model="qwen-plus",  # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
                messages=[
                    {'role': 'system', 'content': system_content},
                    {'role': 'user', 'content': user_content}
                ],
                stream=False,  # 设置为 False，直接返回完整响应
            )
            
            # 获取模型响应
            assistant_message = completion.choices[0].message.content
            print(assistant_message)
            
            # 如果响应包含</think>标签，提取有效内容
            think_match = re.findall(r"</think>(.*)", assistant_message, re.DOTALL)
            if think_match:
                assistant_message = think_match[0].strip()
            
            # 生成新的会话ID（如果需要）
            new_session_id = session_id if session_id else f"debate_{hash(topic) % 10000}"
            
        except Exception as e:
            print(f"API调用错误：{e}")
            return Response(
                {"error": f"API调用失败: {str(e)}"}, 
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        return Response({
            "message": assistant_message,
            "session_id": new_session_id,
            "ai_side": ai_side,
            "topic": topic
        }, status=status.HTTP_200_OK)
